package com.ideaaedi.zoo.commonbase.context;


import com.ideaaedi.zoo.commonbase.component.tenant.TenantScope;
import com.ideaaedi.zoo.commonbase.component.tenant.UserIdAndTenantScope;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.tuple.Pair;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Map;

/**
 * zoo context实现提供器
 * <p>
 * 注：相关能力按功能分组，减少使用复杂度
 * </p>
 *
 * @author <font size = "20" color = "#3CAA3C"><a href="https://gitee.com/JustryDeng">JustryDeng</a></font> <img
 * src="https://gitee.com/JustryDeng/shared-files/raw/master/JustryDeng/avatar.jpg" />
 * @since 1.4.4
 */
public interface ZcProvider {
    
    /**
     * 获取线程的上下文
     *
     * @return 线程的上下文
     */
    @Nonnull
    Map<String, Object> unmodifiableContext();
    
    /**
     * 清除所有线程上下文信息
     */
    void clear();
    
    /**
     * {@link Inner}实现者
     */
    Inner provideInner();
    
    /**
     * {@link Http}实现者
     */
    Http provideHttp();
    
    /**
     * {@link Auth}实现者
     *
     * @param inner 操作上下文的内部能力
     */
    Auth provideAuth(ZcProvider.Inner inner);
    
    /**
     * {@link TenantCt}实现者
     *
     * @param inner 操作上下文的内部能力
     */
    TenantCt provideTenantCt(ZcProvider.Inner inner);
    
    /**
     * {@link AuditLog}实现者
     *
     * @param inner 操作上下文的内部能力
     */
    AuditLog provideAuditLog(ZcProvider.Inner inner);
    
    /**
     * {@link Complex}实现者
     *
     * @param auth 用户数据能力
     * @param tenantCt 租户数据域能力
     */
    Complex provideComplex(ZcProvider.Auth auth, ZcProvider.TenantCt tenantCt);
    

    
    /**
     * 操作上下文的内部能力
     */
    interface Inner {
        
        /**
         * 添加一个键值对到当前线程的上下文中
         */
        void put(String key, Object value);
        
        /**
         * 上下文中获取指定key的值
         */
        @Nullable
        <T> T get(String key);
        
        /**
         * 清除
         */
        void remove(String key, String... moreKeys);
        
        /*
         * 获取线程的上下文
         *
         * @return 线程的上下文
         */
        @Nonnull
        Map<String, Object> context();
        
        /*
         * 清空上下文
         */
        void clear();
    }
    
    /**
     * 对其他能力进行组装而来的复合能力
     */
    interface Complex {
        
        /**
         * 设置数据域租户值到请求attributes
         *
         * @see #setUserIdAndTenantScope(Long, TenantScope)
         */
        <T extends UserIdAndTenantScope> void setUserIdAndTenantScope(@Nonnull T specUserTenant);
        
        /**
         * 设置用户id、用户数据域租户值到请求attributes
         *
         * @param userId 用户id
         * @param tenantScope 数据域租户值
         */
        void setUserIdAndTenantScope(@Nonnull Long userId, @Nullable TenantScope tenantScope);
        
        /**
         * 清除用户id、数据域租户值，并返回清空的值
         *
         * @return <ul>
         * <li>左：用户id</li>
         * <li>右-数据域租户值</li>
         * </ul>
         */
        @Nonnull
        Pair<Long, TenantScope> clearUserInfo();
        
        /**
         * 清除用户id、数据域信息
         *
         * @param specUserTenant 指定清除用户与租户(注：当用户id匹配时才清除)
         */
        void clear(@Nullable UserIdAndTenantScope specUserTenant);
    }
    
    /**
     * 租户相关
     */
    interface TenantCt {
        
        /**
         * 设置当前登录用户的租户域信息
         */
        void setTenantScope(@Nullable TenantScope tenantScope);
        
        /**
         * 获取用户数据域
         *
         * @return 当前登录用户数据域
         */
        @Nullable
        TenantScope currTenantScope();
        
        /**
         * 获取用户数据域
         *
         * @return 当前登录用户数据域
         */
        @Nonnull
        TenantScope currTenantScopeNonNull();
        
        /**
         * 获取用户数据insert域
         * <p>
         * 这也是用户所属租户域
         * </p>
         *
         * @return 用户数据insert域
         */
        @Nullable
        String currInsertTenant();
        
        /**
         * 获取用户数据写入域
         * <p>
         * 这也是用户所属租户域
         * </p>
         *
         * @return 用户数据写入域
         */
        @Nonnull
        String currInsertTenantNonNull();
        
        /**
         * 获取用户数据查询域
         *
         * @return 用户数据查询域
         */
        @Nullable
        Collection<String> currReadableTenants();
        
        /**
         * 获取用户数据修改/删除域
         *
         * @return 用户数据修改/删除域
         */
        @Nullable
        Collection<String> currModifiableTenants();
        
        /**
         * 清除上下文中当前登录用户的租户数据域记录
         */
        void clear();
    }
    
    /**
     * 认证鉴权相关
     */
    interface Auth {
        
        /**
         * 设置当前登录的用户id
         */
        void setUserId(@Nullable Long userId);
        
        /**
         * 获取用户id
         *
         * @return 用户id
         */
        @Nullable
        Long currUserId();
        
        /**
         * 获取用户id
         *
         * @return 用户id
         */
        @Nullable
        Long currUserIdDefault(Long defaultValue);
        
        /**
         * 获取用户id
         *
         * @return 用户id
         */
        @Nonnull
        Long currUserIdNonNull();
        
        /**
         * 清除上下文中当前登录用户的id记录
         */
        void clear();
    }
    
    /**
     * 审计日志相关
     */
    interface AuditLog {
        
        /**
         * 设置当前最新的审计日志id
         */
        void setLatestAuditLogId(Long id);
        
        /**
         * 获取http请求
         */
        @Nullable
        Long latestAuditLogId();
    }
    
    /**
     * http相关
     */
    interface Http {
        
        /**
         * 获取http请求
         */
        @Nullable
        HttpServletRequest httpServletRequest();
        
        /**
         * 获取http响应
         */
        HttpServletResponse httpServletResponse();
        
        /**
         * 设置请求Attribute
         */
        void setAttribute(String key, Object value);
        
        /**
         * 从请求中获取Attribute
         */
        <T> T getAttribute(String key);
        
        /**
         * 获取客户端ip
         */
        @Nullable
        String clientIpAddress();
        
        /**
         * 获取客户端ip
         */
        @Nullable
        String clientIpAddress(@Nullable HttpServletRequest httpServletRequest);
    }
}